﻿using Microsoft.AspNetCore.JsonPatch.Operations;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.EntityFrameworkCore.ChangeTracking;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Newtonsoft.Json.Linq;
using Qianke.Core.Common;
using Qianke.Core.Common.Enum;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Diagnostics;
using System.Linq;
using System.Net.Http.Json;
using System.Text;
using System.Threading.Tasks;
using Volo.Abp.Auditing;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Domain.Entities.Events;
using static Microsoft.AspNetCore.Razor.Language.TagHelperMetadata;

namespace Qianke.Core.Saas.WebApi.SaasExtensions.SaasAuditing
{
    [Dependency(ReplaceServices = true)]
    public class SaasAuditingStore : IAuditingStore, ITransientDependency
    {
        private readonly IOptions<SaasAuditingOptions> options;
        private readonly ILogger<SaasAuditingStore> logger;

        public SaasAuditingStore(IOptions<SaasAuditingOptions> options, ILogger<SaasAuditingStore> logger)
        {
            this.options = options;
            this.logger = logger;
        }

        public Task SaveAsync(AuditLogInfo auditInfo)
        {
            var sessionId = Guid.NewGuid();
            //数据变动日志
            _ = Task.Run(() => WriteApiCallLog(sessionId, auditInfo));
            _ = Task.Run(() => WriteDataChangeLog(sessionId, auditInfo));
            return Task.CompletedTask;
        }

        private async Task WriteApiCallLog(Guid id, AuditLogInfo auditInfo)
        {
            if (string.IsNullOrEmpty(options.Value.ApiLogUrl))
                return;
            if (!(bool)auditInfo.ExtraProperties.GetValueOrDefault("WriteCallApiLog", false))
                return;

            var createTime = auditInfo.ExecutionTime;
            var useTime = auditInfo.ExecutionDuration;
            var ip = auditInfo.ClientIpAddress;
            var paramInfo = auditInfo.ExtraProperties.GetValueOrDefault("ApiParamInfo");
            var returnValue = auditInfo.ExtraProperties.GetValueOrDefault("ApiReturnValue");
            var tokenInfo = auditInfo.ExtraProperties.GetValueOrDefault("TokenInfo");
            var apiUrl = auditInfo.ExtraProperties.GetValueOrDefault("ApiUrl", auditInfo.Url);


            using (var httpClient = new HttpClient())
            {
                try
                {
                    var httpContent = new StringContent(new
                    {
                        Action = "out",
                        LogInfo = new
                        {
                            ApiUrl = apiUrl,
                            Id = id,
                            MessageId = id,
                            ProjectName = auditInfo.ApplicationName,
                            ParamInfo = paramInfo,
                            ResultInfo = returnValue,
                            InTime = auditInfo.ExecutionTime,
                            TokenInfo = tokenInfo, //明文的Token信息
                            OutTime = auditInfo.ExecutionTime.AddMicroseconds(auditInfo.ExecutionDuration),
                            UseTime = auditInfo.ExecutionDuration,
                            DelTime = auditInfo.EntityChanges.Count > 0 ? auditInfo.ExecutionTime.AddYears(1) : auditInfo.ExecutionTime.AddDays(1),
                        }
                    }.ToJson(),Encoding.UTF8,"application/json");
                    var response = await httpClient.PostAsync(options.Value.ApiLogUrl, httpContent);
                    var str = await response.Content.ReadAsStringAsync();
                    Trace.WriteLine(str);
                }
                catch (Exception ex)
                {
                    logger.LogError($"API调用日志上传失败：{auditInfo.ToJson()}", ex);
                }
            }
        }

        private async Task WriteDataChangeLog(Guid id, AuditLogInfo auditInfo)
        {
            if (string.IsNullOrEmpty(options.Value.DataChangeUrl))
                return;
            if (auditInfo.EntityChanges.Count == 0)
                return;
            foreach (var entity in auditInfo.EntityChanges)
            {
                var optionType = OptionTypeEnum.新增;
                switch (entity.ChangeType)
                {
                    case EntityChangeType.Deleted:
                        optionType = OptionTypeEnum.删除;
                        break;
                    case EntityChangeType.Updated:
                        optionType = OptionTypeEnum.修改;
                        break;
                }

                var tokenInfo = auditInfo.ExtraProperties.GetValueOrDefault("TokenInfo");
                using (var httpClient = new HttpClient())
                {
                    try
                    {

                        var entityEntry = entity.EntityEntry as EntityEntry;
                        var tabName = entityEntry?.CurrentValues.EntityType.ShortName();
                        var obj = entityEntry?.CurrentValues.ToObject();

                        var postData = new
                        {
                            MessageId = id,
                            TokenInfo = tokenInfo,
                            TabName = tabName,
                            TabAnnotation = "",
                            DataId = entity.EntityId,
                            OrganId = 0,
                            OperationId = 0,
                            OperationName = "",
                            DataType = optionType,
                            Content = obj.ToJson(),
                            CreateTime = auditInfo.ExecutionTime
                        }.ToJson();

                        var httpContent = new StringContent(postData,Encoding.UTF8,"application/json");
                        var response = await httpClient.PostAsync(options.Value.DataChangeUrl, httpContent);
                        var result = await response.Content.ReadFromJsonAsync<ReturnInfoData<JToken>>();
                        if (result?.resultcode != "200")
                        {
                            logger.LogInformation($"模型变动日志上传失败：{result?.resultcontent}");
                            logger.LogInformation($"日志内容：{postData}");
                        }
                    }
                    catch (Exception ex)
                    {
                        logger.LogError($"数据变动日志上传失败：{auditInfo.ToJson()}", ex);
                    }
                }
            }


        }
    }
}
